package org.example;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.BitSet;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import Back.CarPathInfo;
import Back.ReplaySelectorFrame;
import Dao.dt;
import aaa.MapDataService;
import aaa.RedisMapRepository;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;
import redis.clients.jedis.resps.Tuple;

public class MainMenu extends JFrame {
    public MainMenu() {
        initUI();
    }

    private void initUI() {
        setTitle("路径规划系统 v5.0");
        setSize(300, 200);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        JPanel panel = new JPanel(new GridLayout(2, 1, 10, 10));
        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        JButton editorBtn = new JButton("自定义地图探索");
        JButton explorerBtn = new JButton("已定义地图探索");

        editorBtn.addActionListener(e -> {
            new MapEditor().setVisible(true); // 传递currentUser
            dispose();
        });

        explorerBtn.addActionListener(e -> {
            new MapExplorer().setVisible(true);
            dispose();
        });

        panel.add(editorBtn);
        panel.add(explorerBtn);
        add(panel);
    }
}

 class MapEditor extends JFrame {
    private EditableMapPanel mapPanel;
    private JSpinner rowSpinner, colSpinner, carSpinner;
    private User currentUser;
    // 1. 声明为成员变量
    private JComboBox<String> algorithmComboBox;

    // 添加带参数的构造函数
    public MapEditor() {

        initEditorUI();
    }

    private void initEditorUI() {
        setTitle("自定义地图探索");
        setSize(800, 800);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null);
        setLayout(new BorderLayout(5, 5));

        JPanel controlPanel = new JPanel();
        controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.Y_AXIS));
        controlPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        // 尺寸设置面板
        JPanel sizePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        sizePanel.add(new JLabel("行数:"));
        rowSpinner = new JSpinner(new SpinnerNumberModel(10, 1, 100, 1));
        sizePanel.add(rowSpinner);

        sizePanel.add(new JLabel("列数:"));
        colSpinner = new JSpinner(new SpinnerNumberModel(10, 1, 100, 1));
        sizePanel.add(colSpinner);

        JButton sizeBtn = new JButton("应用尺寸");
        sizeBtn.addActionListener(this::handleResize);
        sizePanel.add(sizeBtn);

        // 小车设置面板
        JPanel carPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        carPanel.add(new JLabel("小车数量:"));
        carSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 20, 1));
        carPanel.add(carSpinner);

        JButton saveBtn = new JButton("载入地图");
        saveBtn.addActionListener(this::saveToRedis);
        carPanel.add(saveBtn);

        // 添加开始探索按钮
        JButton exploreBtn = new JButton("开始探索");
        exploreBtn.addActionListener(e -> startRealTimeMap());
        carPanel.add(exploreBtn);

        // 障碍物设置面板
        JPanel obstaclePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        obstaclePanel.add(new JLabel("障碍物数量:"));
        JSpinner obsSpinner = new JSpinner(new SpinnerNumberModel(10, 0, 1000, 1));
        obstaclePanel.add(obsSpinner);

        JButton randomObsBtn = new JButton("随机添加");
        randomObsBtn.addActionListener(e -> {
            int count = (Integer) obsSpinner.getValue();
            mapPanel.randomizeObstacles(count);
        });
        obstaclePanel.add(randomObsBtn);

        // === 新增：算法选择面板 ===
        JPanel algPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        algPanel.add(new JLabel("路径规划算法:"));
        algorithmComboBox = new JComboBox<>(new String[]{"A*", "AA*","BFS"});
        algorithmComboBox.setSelectedIndex(0); // 默认选择A*
        algPanel.add(algorithmComboBox);

        // 导航面板
        JPanel navPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        JButton backBtn = new JButton("返回主菜单");
        backBtn.addActionListener(e -> {
            new MainMenu().setVisible(true);
            dispose();
        });
        navPanel.add(backBtn);

        // 添加到控制面板
        controlPanel.add(sizePanel);
        controlPanel.add(Box.createVerticalStrut(10));
        controlPanel.add(carPanel);
        controlPanel.add(Box.createVerticalStrut(10));
        controlPanel.add(obstaclePanel);
        controlPanel.add(Box.createVerticalStrut(10));
        controlPanel.add(navPanel);
        controlPanel.add(Box.createVerticalStrut(10));
        controlPanel.add(algPanel);

        mapPanel = new EditableMapPanel(10, 10);
        add(controlPanel, BorderLayout.NORTH);
        add(new JScrollPane(mapPanel), BorderLayout.CENTER);
    }

    private void startRealTimeMap() {
        new RealTimeMapFrame(currentUser).setVisible(true);
    }

    private void handleResize(ActionEvent e) {
        int newRows = (Integer) rowSpinner.getValue();
        int newCols = (Integer) colSpinner.getValue();
        mapPanel.updateGrid(newRows, newCols);
    }

    private void saveToRedis(ActionEvent e) {
        String mapName = "map"; // 直接使用默认地图名称 "map"
        int carCount = (Integer) carSpinner.getValue();
        new MapSaver(mapName, carCount).execute();
    }

    private class MapSaver extends SwingWorker<Void, Void> {
        private final String mapName;
        private final int carCount;
        private final String algorithm; // 存储算法名称

        public MapSaver(String mapName, int carCount) {
            this.mapName = mapName;
            this.carCount = carCount;
            this.algorithm = (String) algorithmComboBox.getSelectedItem();
        }

        @Override
        protected Void doInBackground() {
            try (Jedis jedis = new Jedis("localhost", 6379)) {
                // 获取地图数据
                int rows = mapPanel.getRows();
                int cols = mapPanel.getCols();
                BitSet obstacles = mapPanel.getObstacleBits();

                // 存储基础信息
                jedis.set("mapwidth", String.valueOf(cols));
                jedis.set("mapheight", String.valueOf(rows));
                // 存储算法到Redis ===
                jedis.set("map:alg", algorithm);

                // 生成小车位置
                Map<String, String> carPositions = generateCarPositions(rows, cols, obstacles, carCount);

                // 初始化视野数据
                BitSet lightBits = new BitSet(rows * cols);
                initializeLightData(lightBits, carPositions, rows, cols);

                // 存储到Redis
                storeRedisData(jedis, rows, cols, obstacles, lightBits, carPositions);

                SwingUtilities.invokeLater(() ->
                        JOptionPane.showMessageDialog(MapEditor.this,
                                "数据保存成功！\n" +
                                        "地图尺寸：" + cols + "x" + rows + "\n" +
                                        "小车位置：" + carPositions + "\n" +
                                        "初始点亮区域：" + formatLightBits(lightBits, rows, cols))
                );
            } catch (Exception ex) {
                ex.printStackTrace();
                SwingUtilities.invokeLater(() ->
                        JOptionPane.showMessageDialog(MapEditor.this, "错误：" + ex.getMessage())
                );
            }
            return null;
        }

        private void initializeLightData(BitSet lightBits, Map<String, String> carPositions,
                                         int rows, int cols) {
            // 遍历所有小车位置
            for (String position : carPositions.values()) {
                String[] coord = position.split(",");
                int x = Integer.parseInt(coord[0]);
                int y = Integer.parseInt(coord[1]);
                updateLightAroundCar(lightBits, x, y, rows, cols);
            }
        }


        private void updateLightAroundCar(BitSet lightBits, int x, int y,
                                          int rows, int cols) {
            for (int dy = -1; dy <= 1; dy++) {
                for (int dx = -1; dx <= 1; dx++) {
                    int nx = x + dx;
                    int ny = y + dy;

                    // 检查边界
                    if (nx >= 0 && nx < cols && ny >= 0 && ny < rows) {
                        int index = ny * cols + nx;
                        lightBits.set(index);
                    }
                }
            }
        }

        private void storeRedisData(Jedis jedis, int rows, int cols, BitSet obstacles,
                                    BitSet lightBits, Map<String, String> carPositions) {

            // 清除旧的小车位置数据
            for (int i = 1; i <= 10; i++) { // 假设最大小车数量为10
                String key = "car:" + i + ":position";
                if (jedis.exists(key)) {
                    jedis.del(key);
                }
            }

            // 存储障碍物（字符串格式）
            String obstacleData = RedisUtils.bitSetToString(obstacles, rows, cols);
            jedis.set("map:obstacle", obstacleData);

            // 存储视野数据（字符串格式）
            String lightData = RedisUtils.bitSetToString(lightBits, rows, cols);
            jedis.set("map:light", lightData);

            // 存储小车位置
            for (Map.Entry<String, String> entry : carPositions.entrySet()) {
                String carId = entry.getKey().replace("car", "");
                String[] coordinates = entry.getValue().split(",");
                jedis.hset("car:" + carId + ":position",
                        new HashMap<String, String>() {{
                            put("x", coordinates[0]);
                            put("y", coordinates[1]);
                        }}
                );
            }
            //存储小车数量
            jedis.set("carcount", String.valueOf(carCount));
        }

        private String formatLightBits(BitSet bits, int rows, int cols) {
            return RedisUtils.formatBitSet(bits, rows, cols);
        }
    }
    private Map<String, String> generateCarPositions(int rows, int cols,
                                                     BitSet obstacles, int count) {
        Map<String, String> cars = new LinkedHashMap<>();
        ArrayList<Point> available = new ArrayList<>();

        // 收集可用位置
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                int index = y * cols + x;
                if (!obstacles.get(index)) {
                    available.add(new Point(x, y));
                }
            }
        }

        // 验证空间
        if (available.size() < count) {
            throw new RuntimeException("需要" + count + "个位置，但只有" + available.size() + "个可用");
        }

        // 随机选择位置
        Collections.shuffle(available);
        for (int i = 0; i < count; i++) {
            Point p = available.get(i);
            cars.put("car" + (i+1), p.x + "," + p.y);
        }
        return cars;
    }
}

class MapExplorer extends JFrame {
    private ReadonlyMapPanel mapPanel;
    private JComboBox<String> mapSelector;
    private JSpinner carSpinner;
    private JButton loadBtn;
    // 添加算法选择框成员变量
    private JComboBox<String> algorithmComboBox;
    private static final String JDBC_URL = "jdbc:mysql://localhost:3306/db?useSSL=false";
    private static final String DB_USER = "root";
    private static final String DB_PASSWORD = "123456";
    private User currentUser;
    static {
        try {
            // 尝试使用新版驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            try {
                // 如果失败，尝试旧版驱动
                Class.forName("com.mysql.jdbc.Driver");
            } catch (ClassNotFoundException ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(null, "MySQL驱动加载失败: " + ex.getMessage());
            }
        }
    }

    public MapExplorer() {
        initUI();
    }

    private void initUI() {
        setTitle("已定义地图探索");
        setSize(800, 600);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null);
        setLayout(new BorderLayout(10, 10));

        // 控制面板
        JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));
        controlPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        // 地图选择组件
        mapSelector = new JComboBox<>();
        controlPanel.add(new JLabel("选择地图:"));
        controlPanel.add(mapSelector);

        // 小车数量选择器
        controlPanel.add(new JLabel("小车数量:"));
        carSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 20, 1));
        controlPanel.add(carSpinner);

        // === 算法选择组件 ===
        controlPanel.add(new JLabel("算法:"));
        algorithmComboBox = new JComboBox<>(new String[]{"A*", "AA*","BFS"});
        algorithmComboBox.setSelectedIndex(0); // 默认选择A*
        controlPanel.add(algorithmComboBox);

        // 载入地图按钮
        loadBtn = new JButton("载入地图");
        loadBtn.addActionListener(e -> handleLoadMap());
        controlPanel.add(loadBtn);

        // 开始探索按钮
        JButton exploreBtn = new JButton("开始探索");
        exploreBtn.addActionListener(e -> new RealTimeMapFrame(currentUser).setVisible(true));
        controlPanel.add(exploreBtn);

        // 返回按钮
        JButton backBtn = new JButton("返回主菜单");
        backBtn.addActionListener(e -> returnToMain());
        controlPanel.add(backBtn);

        // 地图显示面板
        mapPanel = new ReadonlyMapPanel();

        add(controlPanel, BorderLayout.NORTH);
        add(new JScrollPane(mapPanel), BorderLayout.CENTER);

        // 从数据库加载可用地图列表
        new SwingWorker<Void, Void>() {
            protected Void doInBackground() {
                loadMapNames();
                return null;
            }
        }.execute();
    }

    private void loadMapNames() {
        try (Connection conn = DriverManager.getConnection(JDBC_URL, DB_USER, DB_PASSWORD)) {
            String sql = "SELECT mapid FROM map";
            try (PreparedStatement stmt = conn.prepareStatement(sql);
                 ResultSet rs = stmt.executeQuery()) {

                Vector<String> mapNames = new Vector<>();
                while (rs.next()) {
                    mapNames.add(rs.getString("mapid"));
                }

                SwingUtilities.invokeLater(() -> {
                    mapSelector.setModel(new DefaultComboBoxModel<>(mapNames));
                    if (!mapNames.isEmpty()) {
                        mapSelector.setSelectedIndex(0);
                        // 自动加载第一张地图
                        loadMapFromDB();
                    }
                });
            }
        } catch (SQLException ex) {
            ex.printStackTrace();
            SwingUtilities.invokeLater(() ->
                    JOptionPane.showMessageDialog(null, "加载地图列表失败: " + ex.getMessage())
            );
        }
    }

    private void loadMapFromDB() {
        String mapName = (String) mapSelector.getSelectedItem();
        if (mapName == null) return;

        new SwingWorker<Void, Void>() {
            protected Void doInBackground() {
                try (Connection conn = DriverManager.getConnection(JDBC_URL, DB_USER, DB_PASSWORD)) {
                    MapData data = fetchMapData(conn, mapName);
                    SwingUtilities.invokeLater(() ->
                            mapPanel.updateGrid(data.height, data.width, data.obstacles)
                    );
                } catch (Exception e) {
                    e.printStackTrace();
                    SwingUtilities.invokeLater(() ->
                            JOptionPane.showMessageDialog(null, "地图加载失败: " + e.getMessage())
                    );
                }
                return null;
            }
        }.execute();
    }

    private MapData fetchMapData(Connection conn, String mapName) throws SQLException {
        String sql = "SELECT mapwidth, mapheight, `map:obstacle` FROM map WHERE mapid = ?";
        try (PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setString(1, mapName);
            ResultSet rs = stmt.executeQuery();
            if (!rs.next()) throw new SQLException("地图不存在");

            int width = rs.getInt("mapwidth");
            int height = rs.getInt("mapheight");
            String obstacleStr = rs.getString("map:obstacle");

            // 如果没有障碍物数据，创建一个空字符串
            if (obstacleStr == null) {
                obstacleStr = "0".repeat(width * height);
            }

            // 确保字符串长度匹配地图尺寸
            int expectedLength = width * height;
            if (obstacleStr.length() < expectedLength) {
                // 不足部分用"0"填充
                obstacleStr = obstacleStr + "0".repeat(expectedLength - obstacleStr.length());
            } else if (obstacleStr.length() > expectedLength) {
                // 截断多余部分
                obstacleStr = obstacleStr.substring(0, expectedLength);
            }

            // 转换字符串为BitSet
            BitSet obstacles = new BitSet(expectedLength);
            for (int i = 0; i < obstacleStr.length(); i++) {
                if (obstacleStr.charAt(i) == '1') {
                    obstacles.set(i);
                }
            }

            return new MapData(width, height, obstacles);
        }
    }

    private void writeToRedis() {
        String mapName = (String) mapSelector.getSelectedItem();
        new SwingWorker<Void, Void>() {
            protected Void doInBackground() {
                try (Connection conn = DriverManager.getConnection(JDBC_URL, DB_USER, DB_PASSWORD);
                     Jedis jedis = new Jedis("localhost", 6379)) {

                    MapData data = fetchMapData(conn, mapName);

                    // 转换为字符串格式存储
                    String obstacleStr = RedisUtils.bitSetToString(
                            data.obstacles, data.height, data.width);
                    jedis.set("map:obstacle", obstacleStr);

                    SwingUtilities.invokeLater(() ->
                            JOptionPane.showMessageDialog(null, "地图数据已写入Redis")
                    );
                } catch (Exception ex) {
                    SwingUtilities.invokeLater(() ->
                            JOptionPane.showMessageDialog(null, "错误: " + ex.getMessage())
                    );
                }
                return null;
            }
        }.execute();
    }

    private void handleLoadMap() {
        String mapName = (String) mapSelector.getSelectedItem();
        int carCount = (Integer) carSpinner.getValue();

        if (mapName == null || mapName.trim().isEmpty()) {
            JOptionPane.showMessageDialog(this, "请先选择地图");
            return;
        }

        new MapLoader(mapName, carCount).execute();
    }

    private class MapLoader extends SwingWorker<Void, Void> {
        private final String mapName;
        private final int carCount;
        private final String algorithm; // 存储算法名称
        private MapData mapData;

        public MapLoader(String mapName, int carCount) {
            this.mapName = mapName;
            this.carCount = carCount;
            // 获取选择的算法
            this.algorithm = (String) algorithmComboBox.getSelectedItem();
        }

        @Override
        protected Void doInBackground() {
            try (Connection conn = DriverManager.getConnection(JDBC_URL, DB_USER, DB_PASSWORD);
                 Jedis jedis = new Jedis("localhost", 6379)) {

                // 从数据库加载地图数据
                mapData = fetchMapData(conn, mapName);

                // 生成小车位置（避开障碍物）
                Map<String, String> carPositions = generateCarPositions(mapData);

                // 计算照明区域
                BitSet lightBits = calculateLightBits(mapData, carPositions);

                // === 新增：存储算法到Redis ===
                jedis.set("map:alg", algorithm);

                // 写入Redis
                writeRedisData(jedis, lightBits, carPositions);

                // 更新UI显示
                SwingUtilities.invokeLater(() -> {
                    mapPanel.updateGrid(mapData.height, mapData.width, mapData.obstacles);
                    JOptionPane.showMessageDialog(MapExplorer.this,
                            "地图载入成功！\n" +
                                    "地图名称：" + mapName + "\n" +
                                    "地图尺寸：" + mapData.width + "x" + mapData.height + "\n" +
                                    "小车数量：" + carCount
                    );
                });
            } catch (Exception ex) {
                ex.printStackTrace();
                SwingUtilities.invokeLater(() ->
                        JOptionPane.showMessageDialog(MapExplorer.this, "错误: " + ex.getMessage())
                );
            }
            return null;
        }

        private Map<String, String> generateCarPositions(MapData data) {
            Map<String, String> cars = new LinkedHashMap<>();
            ArrayList<Point> available = new ArrayList<>();

            // 收集所有可用位置（非障碍物）
            for (int y = 0; y < data.height; y++) {
                for (int x = 0; x < data.width; x++) {
                    int index = y * data.width + x;
                    if (!data.obstacles.get(index)) {
                        available.add(new Point(x, y));
                    }
                }
            }

            // 检查可用位置是否足够
            if (available.size() < carCount) {
                throw new RuntimeException("需要" + carCount + "个位置，但只有" + available.size() + "个可用位置");
            }

            // 随机选择小车位置
            Collections.shuffle(available);
            for (int i = 0; i < carCount; i++) {
                Point p = available.get(i);
                cars.put("car" + (i + 1), p.x + "," + p.y);
            }
            return cars;
        }

        private BitSet calculateLightBits(MapData data, Map<String, String> carPositions) {
            BitSet lightBits = new BitSet(data.width * data.height);

            // 为每个小车位置计算照明区域
            for (String position : carPositions.values()) {
                String[] parts = position.split(",");
                int x = Integer.parseInt(parts[0]);
                int y = Integer.parseInt(parts[1]);

                // 点亮小车周围3x3区域
                for (int dy = -1; dy <= 1; dy++) {
                    for (int dx = -1; dx <= 1; dx++) {
                        int nx = x + dx;
                        int ny = y + dy;

                        // 检查边界
                        if (nx >= 0 && nx < data.width && ny >= 0 && ny < data.height) {
                            int index = ny * data.width + nx;
                            lightBits.set(index);
                        }
                    }
                }
            }
            return lightBits;
        }

        private void writeRedisData(Jedis jedis, BitSet lightBits, Map<String, String> carPositions) {
            // 清除旧数据
            jedis.flushDB();

            // 存储基础地图信息
            jedis.set("mapwidth", String.valueOf(mapData.width));
            jedis.set("mapheight", String.valueOf(mapData.height));
            jedis.set("carcount", String.valueOf(carCount));

            // 存储障碍物数据
            String obstacleData = RedisUtils.bitSetToString(mapData.obstacles, mapData.height, mapData.width);
            jedis.set("map:obstacle", obstacleData);

            // 存储照明数据
            String lightData = RedisUtils.bitSetToString(lightBits, mapData.height, mapData.width);
            jedis.set("map:light", lightData);

            // 存储小车位置
            for (Map.Entry<String, String> entry : carPositions.entrySet()) {
                String carId = entry.getKey().replace("car", "");
                String[] coordinates = entry.getValue().split(",");

                Map<String, String> position = new HashMap<>();
                position.put("x", coordinates[0]);
                position.put("y", coordinates[1]);

                jedis.hset("car:" + carId + ":position", position);
            }
        }
    }

    private void returnToMain() {
        new MainMenu().setVisible(true);
        dispose();
    }

    private static class MapData {
        final int width;
        final int height;
        final BitSet obstacles;

        MapData(int width, int height, BitSet obstacles) {
            this.width = width;
            this.height = height;
            this.obstacles = obstacles;
        }
    }
}

class ReadonlyMapPanel extends JPanel {
    private BitSet grid;
    private int rows, cols;

    public void updateGrid(int rows, int cols, BitSet grid) {
        this.rows = rows;
        this.cols = cols;
        this.grid = grid;
        revalidate();
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (grid == null) return;

        int cellSize = Math.min(getWidth()/cols, getHeight()/rows);
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                int index = y * cols + x;
                g.setColor(grid.get(index) ? Color.BLACK : Color.WHITE);
                g.fillRect(x*cellSize, y*cellSize, cellSize, cellSize);

                g.setColor(Color.LIGHT_GRAY);
                g.drawRect(x*cellSize, y*cellSize, cellSize, cellSize);
            }
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(500, 500);
    }
}
 class RedisUtils {
    // 将BitSet转换为字符串格式
    public static String bitSetToString(BitSet bits, int rows, int cols) {
        StringBuilder sb = new StringBuilder(rows * cols);
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                int index = y * cols + x;
                sb.append(bits.get(index) ? '1' : '0');
            }
        }
        return sb.toString();
    }

    // 将字符串转换为BitSet
    public static BitSet stringToBitSet(String data, int rows, int cols) {
        int totalBits = rows * cols;
        BitSet bits = new BitSet(totalBits);
        for (int i = 0; i < Math.min(data.length(), totalBits); i++) {
            if (data.charAt(i) == '1') {
                bits.set(i);
            }
        }
        return bits;
    }

    // 格式化为可读的网格字符串
    public static String formatBitSet(BitSet bits, int rows, int cols) {
        StringBuilder sb = new StringBuilder("\n");
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                int index = y * cols + x;
                sb.append(bits.get(index) ? "1" : "0");
            }
            if (y < rows - 1) sb.append("\n");
        }
        return sb.toString();
    }
}

class RealTimeMapFrame extends JFrame {
    private MapPanel mapPanel;
    private MapService mapService;
    private ScheduledExecutorService scheduler;
    private ScheduledFuture<?> refreshFuture;
    private User currentUser;


    public RealTimeMapFrame(User currentUser) {
        this.currentUser = currentUser;
        initComponents();
        startRefreshTask();

        // 添加窗口关闭监听器
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                stopRefreshTask();
                dispose();
            }
        });
    }

    private void initComponents() {
        setTitle("实时地图探索");
        setSize(1200, 900);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null);

        mapService = new MapService(new RedisRepository("localhost", 6379));
        mapPanel = new MapPanel(mapService);

        getContentPane().add(mapPanel, BorderLayout.CENTER);

        //添加保存回放数据按钮
        JButton SaveButton = new JButton("保存回放数据");
        SaveButton.addActionListener(e -> {
            RedisMapRepository redisRepo = new RedisMapRepository("localhost", 6379);
            MapDataService mapService = new  MapDataService(redisRepo);
            RedisMapRepository.MapData data = mapService.getCurrentMapData();
            dt dao = new dt();
            dao.connect();
            SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm");
            String timestamp = sdf.format(new Date());
            String replayName = currentUser.getId()+"Replay_" + timestamp;
            int height = data.height;
            int width = data.width;
            int count = data.count;
            double global_time = 0;
            double min_time=10000000;
            String map = redisRepo.getstaticmap();

            List<CarPathInfo> carPaths = new ArrayList<>();
            for (int i = 1; i <= count; i++) {
                List<Tuple> path = redisRepo.getcarpath(String.valueOf(i));
                StringBuilder pathBuilder = new StringBuilder();

                if (path != null) {
                    for (Tuple tuple : path) {
                        String member = tuple.getElement();
                        double score = tuple.getScore();
                        global_time = Math.max(global_time, score);
                        min_time=Math.min(min_time,score);
                        if (pathBuilder.length() > 0) {
                            pathBuilder.append("+");
                        }
                        pathBuilder.append(score).append(":").append(member);
                    }
                }
                carPaths.add(new CarPathInfo(i, pathBuilder.toString()));
            }
            //TODO 数据库插入
            dao.insert(replayName, width, height, map, count, (int) global_time,(int)min_time-1,currentUser.getId());
            for (CarPathInfo info : carPaths) {
                dao.addcar(replayName, info.carId, info.path,currentUser.getId());
            }
            System.out.println("✅ 保存回放数据按钮被点击");
            redisRepo.cleanMapAndCarData();
            dao.closeConnection();
        });
                // 添加返回按钮
        JButton backButton = new JButton("返回");
        backButton.addActionListener(e -> {
            stopRefreshTask();
            dispose(); // 关闭当前窗口
            // 返回主菜单
            new MainMenu().setVisible(true);
        });

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(backButton);
        buttonPanel.add(SaveButton);
        getContentPane().add(buttonPanel, BorderLayout.SOUTH);
    }

    private void startRefreshTask() {
        scheduler = Executors.newScheduledThreadPool(1);
        refreshFuture = scheduler.scheduleAtFixedRate(() -> {
            SwingUtilities.invokeLater(() -> {
                mapPanel.repaint(); // 触发重绘
            });
        }, 0, 500, TimeUnit.MILLISECONDS);
    }

    private void stopRefreshTask() {
        if (refreshFuture != null) {
            refreshFuture.cancel(true);
        }
        if (scheduler != null) {
            scheduler.shutdown();
        }
        if (mapService != null) {
            mapService.close();
        }
    }
}

class MapPanel extends JPanel {
    private final MapService mapService;
    private BufferedImage buffer;
    private long lastRepaintTime = 0;
    private static final long REPAINT_INTERVAL = 200; // 200ms刷新间隔

    // 更新颜色方案 - 更现代柔和的配色
    private static final Color LIGHT_COLOR = new Color(245, 245, 245); // 浅灰白
    private static final Color DARK_COLOR = new Color(0,0,0);         // 黑色
    private static final Color OBSTACLE_COLOR = new Color(200, 0, 0); // 红色
    private static final Color CAR_COLOR = new Color(0, 0, 200);       // 蓝色
    private static final Color GRID_COLOR = new Color(230, 230, 230);  // 浅网格线
    private static final Color TEXT_COLOR = new Color(80, 80, 80);     // 深灰文字
    private static final Color CAR_TEXT_COLOR = new Color(255, 255, 255); // 白色文字

    // 添加渐变效果
    private GradientPaint lightGradient;
    private GradientPaint darkGradient;

    public MapPanel(MapService service) {
        this.mapService = service;
        setDoubleBuffered(true);
        setBackground(new Color(250, 250, 250)); // 设置面板背景色
    }

    @Override
    public void repaint() {
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastRepaintTime > REPAINT_INTERVAL) {
            super.repaint();
            lastRepaintTime = currentTime;
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        if (buffer == null || buffer.getWidth() != getWidth() || buffer.getHeight() != getHeight()) {
            buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
        }

        Graphics2D g2d = buffer.createGraphics();

        // 启用抗锯齿和高质量渲染
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

        // 清除背景
        g2d.setColor(getBackground());
        g2d.fillRect(0, 0, getWidth(), getHeight());

        drawGrid(g2d);
        g.drawImage(buffer, 0, 0, null);
        g2d.dispose();
    }

    private void drawGrid(Graphics2D g) {
        RedisRepository.MapData data = mapService.getCurrentMapData();
        if (data == null || data.width <= 0 || data.height <= 0) {
            drawPlaceholder(g);
            return;
        }

        int width = data.width;     // 列数（x轴方向）
        int height = data.height;   // 行数（y轴方向）

        float cellWidth = (float) getWidth() / width;
        float cellHeight = (float) getHeight() / height;

        // 初始化渐变（需要根据单元格大小动态创建）
        lightGradient = new GradientPaint(0, 0, new Color(220, 240, 255),
                0, cellHeight, LIGHT_COLOR);
        darkGradient = new GradientPaint(0, 0, new Color(50, 54, 62),
                0, cellHeight, DARK_COLOR);

        HashMap<String, Boolean> carMap = data.CarMap;
        HashMap<String,Integer>carId = data.CarId;
        // 绘制标题
        g.setColor(TEXT_COLOR);
        g.setFont(new Font("SansSerif", Font.BOLD, 16));
        String title = "实时地图监控 - " + width + "×" + height + " 网格";
        g.drawString(title, 20, 20);

        for (int y = 0; y < height; y++) {      // 外层是 y
            for (int x = 0; x < width; x++) {   // 内层是 x
                float px = x * cellWidth;
                float py = y * cellHeight;
                String posKey = x + " " + y;

                boolean isLighted = mapService.isLighted(x, y, data);
                boolean isObstacle = mapService.isObstacle(x, y, data);
                boolean isCarHere = carMap != null && carMap.containsKey(posKey);
                // 绘制单元格背景
                if (!isLighted) {
                    g.setPaint(darkGradient);
                } else {
                    g.setPaint(lightGradient);
                }
                g.fillRoundRect((int) px, (int) py,
                        (int) Math.ceil(cellWidth),
                        (int) Math.ceil(cellHeight),
                        8, 8); // 圆角矩形

                // 绘制障碍物（仅在没有车辆的位置绘制）
                if (isLighted && isObstacle && !isCarHere) {
                    // 3D效果
                    g.setColor(OBSTACLE_COLOR.darker());
                    g.fillRoundRect((int)(px + 2), (int)(py + 2),
                            (int)(cellWidth - 4),
                            (int)(cellHeight - 4),
                            6, 6);

                    g.setColor(OBSTACLE_COLOR);
                    g.fillRoundRect((int)(px + 1), (int)(py + 1),
                            (int)(cellWidth - 2),
                            (int)(cellHeight - 2),
                            6, 6);

                    // 添加雪花图标（障碍物标识）
                    g.setColor(Color.WHITE);
                    g.setFont(new Font("SansSerif", Font.BOLD, (int)(cellHeight * 0.6)));
                    g.drawString("❄", (int)(px + cellWidth * 0.3), (int)(py + cellHeight * 0.7));
                }

                // 绘制车辆
                if (isLighted && isCarHere) {
                    // 车辆主体
                    g.setColor(CAR_COLOR);
                    g.fillOval(
                            (int)(px + cellWidth * 0.15),
                            (int)(py + cellHeight * 0.15),
                            (int)(cellWidth * 0.7),
                            (int)(cellHeight * 0.7)
                    );


                    // 添加车辆名称（ID）
                    g.setColor(CAR_TEXT_COLOR);
                    g.setFont(new Font("SansSerif", Font.BOLD, (int)(cellHeight * 0.3)));

                    // 获取车辆ID（从位置键映射）
                  //  String carId = getCarIdFromPosition(posKey, data);
                    String carid = String.valueOf(carId.get(posKey)); // 这里需要根据实际情况获取正确的车辆ID
                    if (carId != null) {
                        // 计算文本位置使其居中
                        FontMetrics fm = g.getFontMetrics();
                        int textWidth = fm.stringWidth(carid);
                        int textHeight = fm.getHeight();

                        int textX = (int)(px + cellWidth * 0.5 - textWidth / 2);
                        int textY = (int)(py + cellHeight * 0.5 + textHeight / 4);

                        g.drawString(carid, textX, textY);
                    }
                }

                // 绘制网格线
                g.setColor(GRID_COLOR);
                g.drawRoundRect((int) px, (int) py,
                        (int) Math.ceil(cellWidth),
                        (int) Math.ceil(cellHeight),
                        8, 8);
            }
        }
    }
    // 根据位置获取车辆ID
    private String getCarIdFromPosition(String position, RedisRepository.MapData data) {
        if (data.CarMap == null) return null;
        if (!data.CarMap.containsKey(position)) return null;

        // 生成一个简单的ID：位置坐标的哈希值
        int hash = position.hashCode();
        return "C" + Math.abs(hash % 100); // 返回类似 "C42" 的ID
    }

    private void drawPlaceholder(Graphics2D g) {
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(Color.BLACK);
        g.drawString("加载地图数据中...", 20, 20);
    }
}
class MapService {
    private final RedisRepository redisRepo;

    public MapService(RedisRepository redisRepo) {
        this.redisRepo = redisRepo;
    }

    public void close() {
        if (redisRepo != null) {
            redisRepo.close();
        }
    }

    public boolean isObstacle(int x, int y, RedisRepository.MapData data) {
        if (data == null || data.obstaclesStr == null) return false;
        if (x < 0 || y < 0 || x >= data.width || y >= data.height) return false;

        long offset = (long) y * data.width + x;
        if (offset >= data.obstaclesStr.length()) return false;

        return data.obstaclesStr.charAt((int) offset) == '1';
    }

    public boolean isLighted(int x, int y, RedisRepository.MapData data) {
        if (data == null || data.lightsStr == null) return false;
        if (x < 0 || y < 0 || x >= data.width || y >= data.height) return false;

        long offset = (long) y * data.width + x;
        if (offset >= data.lightsStr.length()) return false;

        return data.lightsStr.charAt((int) offset) == '1';
    }

    public RedisRepository.MapData getCurrentMapData() {
        return redisRepo.getMapData();
    }
}

class RedisRepository {
    private final JedisPool jedisPool;

    public RedisRepository(String host, int port) {
        this.jedisPool = new JedisPool(host, port);
    }

    public void close() {
        if (jedisPool != null) {
            jedisPool.close();
        }
    }

    public MapData getMapData() {
        try (Jedis jedis = jedisPool.getResource()) {
            Pipeline p = jedis.pipelined();
            Response<String> widthResp = p.get("mapwidth");
            Response<String> heightResp = p.get("mapheight");
            //到时候特判一下小车的坐标
            Response<String> obstacleResp = p.get("map:obstacle");
            Response<String> lightResp = p.get("map:light");
            Response<String> carcount = p.get("carcount");
            p.sync();

            int width = Integer.parseInt(widthResp.get());
            int height = Integer.parseInt(heightResp.get());

            int count = 0;
            HashMap<String, Boolean> CarMap = new HashMap<>();
            HashMap<String, Integer>CarId=new HashMap<>();
            if (carcount != null && carcount.get() != null) {
                count = Integer.parseInt(carcount.get());
                for (int i = 1; i <= count; i++) {
                    String pos = getCarPosition(String.valueOf(i));
                    if (pos != null) {
                        CarMap.put(pos, true);
                        CarId.put(pos,i);
                    }
                }
            }

            String obstaclesStr = obstacleResp.get();
            String lightsStr = lightResp.get();

            return new MapData(width, height, obstaclesStr, lightsStr, count, CarMap,CarId);
        } catch (Exception e) {
            System.err.println("Redis读取失败，使用默认地图大小 10x10");
            return new MapData(10, 10, "", "", 0, null,null);
        }
    }



   public String getCarPosition(String carId) {
        try (Jedis jedis = jedisPool.getResource()) {
            Map<String, String> pos = jedis.hgetAll("car:" + carId + ":position");
            if (pos.isEmpty()) {
                return null;
            }
            String x = pos.get("x");
            String y = pos.get("y");
            return x + " " + y;
        } catch (Exception e) {
            return null;
        }
    }

    public static class MapData {
        public final int width;
        public final int height;
        public final String obstaclesStr;
        public final String lightsStr;
        public final int count;
        public final HashMap<String, Boolean> CarMap;
        public final HashMap<String, Integer> CarId;

        public MapData(int width, int height, String obstaclesStr, String lightsStr, int count, HashMap<String, Boolean> car,HashMap<String,Integer>carid) {
            this.width = width;
            this.height = height;
            this.obstaclesStr = obstaclesStr;
            this.lightsStr = lightsStr;
            this.count = count;
            this.CarMap = car;
            this.CarId=carid;
        }
    }
}

class EditableMapPanel extends JPanel {
    private BitSet grid;
    private int rows, cols;
    private final Set<Point> obstacles = new HashSet<>();
    private Point hoverPoint = new Point(-1, -1);

    public EditableMapPanel(int rows, int cols) {
        initGrid(rows, cols);
        initInteraction();
    }

    private void initGrid(int rows, int cols) {
        this.rows = rows;
        this.cols = cols;
        this.grid = new BitSet(rows * cols);
        updateRedis();
    }

    private void initInteraction() {
        addMouseMotionListener(new MouseAdapter() {
            public void mouseMoved(MouseEvent e) {
                updateHover(e.getX(), e.getY());
            }
        });

        addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                if (SwingUtilities.isLeftMouseButton(e)) {
                    handleClick(e.getX(), e.getY());
                }
            }
        });
    }

    private void handleClick(int x, int y) {
        Point p = convertToGrid(x, y);
        if (isValid(p)) {
            toggleCell(p);
            updateRedis();
            repaint();
        }
    }

    private void toggleCell(Point p) {
        int index = p.y * cols + p.x;
        boolean newState = !grid.get(index);
        grid.set(index, newState);

        if (newState) {
            obstacles.add(new Point(p.x, p.y));
        } else {
            obstacles.remove(new Point(p.x, p.y));
        }
    }

    private void updateHover(int x, int y) {
        Point p = convertToGrid(x, y);
        if (!p.equals(hoverPoint)) {
            hoverPoint = p;
            repaint();
        }
    }

    private Point convertToGrid(int x, int y) {
        int cellSize = getCellSize();
        return new Point(x / cellSize, y / cellSize);
    }

    private boolean isValid(Point p) {
        return p.x >= 0 && p.x < cols && p.y >= 0 && p.y < rows;
    }

    public void updateGrid(int newRows, int newCols) {
        Set<Point> preserved = new HashSet<>();
        for (Point p : obstacles) {
            if (p.x < newCols && p.y < newRows) {
                preserved.add(p);
            }
        }

        this.rows = newRows;
        this.cols = newCols;
        this.grid = new BitSet(newRows * newCols);
        preserved.forEach(p -> grid.set(p.y * cols + p.x));
        obstacles.clear();
        obstacles.addAll(preserved);

        revalidate();
        repaint();
        updateRedis();
    }

    // 随机生成障碍物
    public void randomizeObstacles(int count) {
        // 清除现有障碍物
        clearObstacles();

        List<Point> positions = new ArrayList<>();

        // 收集所有网格位置
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                positions.add(new Point(x, y));
            }
        }

        // 随机打乱位置
        Collections.shuffle(positions);

        // 设置前count个位置为障碍物
        for (int i = 0; i < Math.min(count, positions.size()); i++) {
            Point p = positions.get(i);
            setObstacle(p.x, p.y, true);
        }

        updateRedis();
        repaint();

        // 显示生成结果
        JOptionPane.showMessageDialog(this, "已生成 " + count + " 个随机障碍物");
    }

    // 清除所有障碍物
    private void clearObstacles() {
        grid.clear();
        obstacles.clear();
    }

    // 设置特定位置的障碍物状态
    private void setObstacle(int x, int y, boolean isObstacle) {
        int index = y * cols + x;
        grid.set(index, isObstacle);

        if (isObstacle) {
            obstacles.add(new Point(x, y));
        } else {
            obstacles.remove(new Point(x, y));
        }
    }

    private void updateRedis() {
        new SwingWorker<Void, Void>() {
            protected Void doInBackground() {
                try (Jedis jedis = new Jedis("localhost", 6379)) {
                    // 获取障碍物BitSet
                    BitSet bits = new BitSet(rows * cols);
                    obstacles.forEach(p -> bits.set(p.y * cols + p.x));

                    // 转换为字符串格式存储
                    String obstacleStr = RedisUtils.bitSetToString(bits, rows, cols);
                    jedis.set("map:obstacle", obstacleStr);
                } catch (Exception e) {
                    System.err.println("实时更新失败: " + e.getMessage());
                }
                return null;
            }
        }.execute();
    }

    public BitSet getObstacleBits() {
        BitSet bits = new BitSet(rows * cols);
        obstacles.forEach(p -> bits.set(p.y * cols + p.x));
        return bits;
    }

    public int getRows() { return rows; }
    public int getCols() { return cols; }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        int cellSize = getCellSize();

        // 绘制网格
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                drawCell(g, x, y, cellSize);
            }
        }

        // 悬停效果
        if (hoverPoint.x >= 0 && hoverPoint.x < cols &&
                hoverPoint.y >= 0 && hoverPoint.y < rows) {
            g.setColor(new Color(255, 255, 0, 50));
            g.fillRect(hoverPoint.x * cellSize, hoverPoint.y * cellSize, cellSize, cellSize);
        }
    }

    private void drawCell(Graphics g, int x, int y, int size) {
        int index = y * cols + x;
        g.setColor(grid.get(index) ? Color.BLACK : Color.WHITE);
        g.fillRect(x * size, y * size, size, size);

        g.setColor(Color.LIGHT_GRAY);
        g.drawRect(x * size, y * size, size, size);
    }

    private int getCellSize() {
        return Math.min(getWidth() / cols, getHeight() / rows);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(500, 500);
    }
}